package com.woniuxy.demo.epai.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.woniuxy.demo.epai.common.DateUtil;
import com.woniuxy.demo.epai.dao.*;
import com.woniuxy.demo.epai.model.*;
import com.woniuxy.demo.epai.service.IOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniuxy.demo.epai.vo.OrderVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;


import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 订单信息 服务实现类
 * </p>
 *
 * @author epai
 * @since 2021-04-12
 */
@Service
@Slf4j
@Transactional
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {
    @Resource
    private OrderMapper mapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private MembersMapper membersMapper;
    @Resource
    private WalletMapper walletMapper;
    @Resource
    private BmsTreasureCountMapper bmsTreasureCountMapper;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 提供给前端生成订单的接口
     * @return
     */
    @Override
    public int createOrder(Integer recId,Integer uid) {
        //数据库查询展示订单需要的数据
        OrderVo orderVo = mapper.createOrder(uid,recId);
        log.info("orderVo:{}",orderVo);
        Order order = new Order();
        //数据库新增订单
        if (orderVo.getStatus()==1){
            order.setPid(orderVo.getPid());
            order.setUid(uid);
            order.setPrice(orderVo.getTransactionPrice());
            order.setOrderStatus(1);
            order.setRecId(orderVo.getRecId());
            order.setAuctionBeginTime(orderVo.getStarttime());
            order.setDeadline(orderVo.getDeadline());
            int i = mapper.insertOrder(order);

            //订单支付时间倒计时，参数为
            // 订单id和是否关闭定时，
            // true为开启定时
            //false为关闭定时
            run(order.getId(),true,uid);
            return i;
        }

       return -1;
    }

    /**
     * 根据状态和用户id获取订单信息
     * @return
     */
    @Override
    public List<OrderVo> getOrders(Integer status,Integer uid) {


        //根据用户id和订单状态去redis中查找数据，有数据则返回，没有则去数据库查
        if (!ObjectUtils.isEmpty(findRedisOrderByStatus(uid,status))){
            return findRedisOrderByStatus(uid,status);
        }
        //去数据库中查订单数据
        List<OrderVo> orders = mapper.getOrders(uid, status);
        //将数据库中查到的数据存入redis
        orders.forEach(orderVo -> {
            insertRedisOrder(orderVo,uid);
        });
        return orders;
    }
    //根据用户id获取全部订单
    @Override
    public List<OrderVo> getAllOrders(Integer uid) {

        //去redis中查，如果有数据则返回
        if (!ObjectUtils.isEmpty(findRedisOrders(uid))){
            return findRedisOrders(uid);
        }
        //去数据库中查
        List<OrderVo> orders = mapper.getAllOrders(uid);
        //将数据库中查到的数据存入redis
        orders.forEach(orderVo -> {
            System.out.println("*********///"+orderVo);
            insertRedisOrder(orderVo,uid);
        });

        return orders;
    }
    /**
     * 订单支付时间倒计时（订单创建时执行，支付成功后关闭）
     *true为开启计时，false为关闭计时
     */
    @Override
    public void run(Integer oid,boolean b,Integer uid) {


        //开始时间
        long start = System.currentTimeMillis();
        //结束时间
        final long end = start + 5 * 60 * 1000;
        final Timer timer = new Timer();
        if (!b){
            System.out.println("关闭计时");
            timer.cancel();
            return;
        }
        int a = 1;
        System.out.println("开启计时");
        //延迟0毫秒（即立即执行）开始，每隔1000毫秒执行一次
        timer.schedule(new TimerTask() {
            public void run() {
                log.info("此处实现倒计时每隔1秒执行一次该任务");
            }
        }, 0, 1000);
        //计时结束时候，停止全部timer计时计划任务
        timer.schedule(new TimerTask() {
            public void run() {
                //修改数据库的订单状态为3
                mapper.updateOrderStaus(3,oid);
                //修改redis中order状态为3
                updateRedisOrderStatus(oid,3);
                User user = userMapper.selectById(uid);
                if(user.getIsVIP()==1){
                    //调整用户的信用分和会员成长值
                    QueryWrapper<Members> membersQueryWrapper = new QueryWrapper<>();
                    membersQueryWrapper.eq("uid",uid);
                    Members members = membersMapper.selectOne(membersQueryWrapper);
                    //信用积分加2
                    members.setCredit(members.getCredit()-2);
                    //会员成长值加成交金额的10%
                    Order order = mapper.selectById(oid);

                    int i = order.getPrice().intValue();
                    Double v = (i * 0.1);
                    int i1 = v.intValue();
                    members.setGrouth(members.getGrouth()-i1);
                    //将修改后的值传入数据库
                    membersMapper.updateById(members);

                }
                //扣除用户的保证金
                //获取订单商品保证金
                OrderVo bond = mapper.findBond(oid);
                //获取用户钱包冻结的保证金
                QueryWrapper<Wallet> walletQueryWrapper = new QueryWrapper<>();
                walletQueryWrapper.eq("uid",uid);
                Wallet wallet = walletMapper.selectOne(walletQueryWrapper);
                //运算（根据该订单缴纳的保证金去钱包中的保证金）
                BigDecimal subtract = wallet.getGuartantee().subtract(bond.getBond());
                //
                wallet.setGuartantee(subtract);
                //数据库修改保证金的金额
                walletMapper.update(wallet,walletQueryWrapper);
                //将扣除的保证金金额存往后台钱包
                BmsTreasureCount bmsTreasureCount = new BmsTreasureCount();
                bmsTreasureCount.setOid(oid);
                bmsTreasureCount.setAmount(bond.getBond());
                bmsTreasureCount.setType("保证金");
                bmsTreasureCountMapper.insert(bmsTreasureCount);
                timer.cancel();
            }

        }, new Date(end));


    }
    //将全部订单存入redis
    @Override
    public boolean insertRedisOrder(OrderVo orderVo,Integer uid) {


        //创建hash操作工具
        HashOperations<String, Object, Object> hashOperations = stringRedisTemplate.opsForHash();
        //判断是否存在该key
        Boolean hasKey = stringRedisTemplate.hasKey("epai:order:" + orderVo.getOid());
        //判断这个key
        if (hasKey){
            //已存在返回false
            return false;
        }else{
            //创建一个hash存储该订单的数据
            HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
            //存入数据
            objectObjectHashMap.put("image",orderVo.getImage());
            objectObjectHashMap.put("productName",orderVo.getProductName());
            objectObjectHashMap.put("introduce",orderVo.getIntroduce());
            objectObjectHashMap.put("basePrice",orderVo.getBasePrice().toString());
            objectObjectHashMap.put("price",orderVo.getPrice().toString());
            objectObjectHashMap.put("address",orderVo.getAddress());
            objectObjectHashMap.put("starttime",DateUtil.dateToString(orderVo.getStarttime()));
            objectObjectHashMap.put("deadline",DateUtil.dateToString(orderVo.getDeadline()));
            objectObjectHashMap.put("bond",orderVo.getBond().toString());
            objectObjectHashMap.put("pid",orderVo.getPid().toString());
            objectObjectHashMap.put("oid",orderVo.getOid().toString());
            objectObjectHashMap.put("orderStatus",orderVo.getOrderStatus().toString());
            objectObjectHashMap.put("uid",uid.toString());
            if (!ObjectUtils.isEmpty(orderVo.getRecId())){
                objectObjectHashMap.put("recId",orderVo.getRecId().toString());
            }
            if (!ObjectUtils.isEmpty(orderVo.getTransactionPrice())){
                objectObjectHashMap.put("transactionPrice",orderVo.getTransactionPrice().toString());

            }
            //将map存入
            System.out.println(objectObjectHashMap.toString());
            //设置过期时间

            stringRedisTemplate.expire("epai:order:"+orderVo.getOid(),60, TimeUnit.HOURS);
            hashOperations.putAll("epai:order:"+orderVo.getOid(),objectObjectHashMap);

            //创建一个List操作工具
            ListOperations<String, String> listOperations = stringRedisTemplate.opsForList();
            //设置过期时间
            stringRedisTemplate.expire("epai:order:uid:"+uid,60, TimeUnit.HOURS);
            listOperations.rightPush("epai:order:uid:"+uid,orderVo.getOid().toString());


            return true;
        }
    }
    //根据状态从redis中查询订单数据
    @Override
    public List<OrderVo> findRedisOrderByStatus(Integer uid,Integer status) {
        //创建list操作工具
        ListOperations<String, String> listOperations = stringRedisTemplate.opsForList();
        //查出所有订单信息
        List<String> range = listOperations.range("epai:order:uid:" + uid, 0, -1);
        //获取hash的操作对象
        HashOperations<String, Object, Object> hashOperations = stringRedisTemplate.opsForHash();
        //创建集合保存订单信息
        List<OrderVo> orderVos = new ArrayList<>();
        //遍历
        range.forEach(id ->{
            //存放数据
            if (Integer.parseInt(hashOperations.get("epai:order:"+id,"orderStatus").toString())==status){


            OrderVo orderVo = new OrderVo();
            orderVo.setOid(Integer.parseInt(hashOperations.get("epai:order:"+id,"oid").toString()));
            orderVo.setDeadline(DateUtil.stringToDate(hashOperations.get("epai:order:"+id,"deadline").toString()));
            orderVo.setAddress(hashOperations.get("epai:order:"+id,"address").toString());
            orderVo.setImage(hashOperations.get("epai:order:"+id,"image").toString());
            orderVo.setIntroduce(hashOperations.get("epai:order:"+id,"introduce").toString());
            orderVo.setProductName(hashOperations.get("epai:order:"+id,"productName").toString());
            orderVo.setOrderStatus(Integer.parseInt(hashOperations.get("epai:order:"+id,"orderStatus").toString()));
            orderVo.setPid(Integer.parseInt(hashOperations.get("epai:order:"+id,"pid").toString()));
            if (!ObjectUtils.isEmpty(orderVo.getRecId())) {
                orderVo.setRecId(Integer.parseInt(hashOperations.get("epai:order:"+id,"recId").toString()));
            }
            orderVo.setBasePrice(new BigDecimal(hashOperations.get("epai:order:"+id,"basePrice").toString()));
            orderVo.setBond(new BigDecimal(hashOperations.get("epai:order:"+id,"bond").toString()));
            orderVo.setPrice(new BigDecimal(hashOperations.get("epai:order:"+id,"price").toString()));
            orderVo.setStarttime(DateUtil.stringToDate(hashOperations.get("epai:order:"+id,"starttime").toString()));
            if (!ObjectUtils.isEmpty(orderVo.getTransactionPrice())){
                orderVo.setTransactionPrice(new BigDecimal(hashOperations.get("epai:order:"+id,"transactionPrice").toString()));
            }
            //将订单信息存入集合
            orderVos.add(orderVo);
            }

        });


        return orderVos;
    }
    //从redis中查询所有订单
    @Override
    public List<OrderVo> findRedisOrders(Integer uid) {
        //创建list操作工具
        ListOperations<String, String> listOperations = stringRedisTemplate.opsForList();
        //查出所有订单信息
        List<String> range = listOperations.range("epai:order:uid:" + uid, 0, -1);
        //获取hash的操作对象
        HashOperations<String, Object, Object> hashOperations = stringRedisTemplate.opsForHash();
        //创建集合保存订单信息
        List<OrderVo> orderVos = new ArrayList<>();
        //遍历
        range.forEach(id ->{
            //存放数据

            OrderVo orderVo = new OrderVo();
            orderVo.setOid(Integer.parseInt(hashOperations.get("epai:order:"+id,"oid").toString()));
            orderVo.setDeadline(DateUtil.stringToDate(hashOperations.get("epai:order:"+id,"deadline").toString()));
            orderVo.setAddress(hashOperations.get("epai:order:"+id,"address").toString());
            orderVo.setImage(hashOperations.get("epai:order:"+id,"image").toString());
            orderVo.setIntroduce(hashOperations.get("epai:order:"+id,"introduce").toString());
            orderVo.setProductName(hashOperations.get("epai:order:"+id,"productName").toString());
            orderVo.setOrderStatus(Integer.parseInt(hashOperations.get("epai:order:"+id,"orderStatus").toString()));
            orderVo.setPid(Integer.parseInt(hashOperations.get("epai:order:"+id,"pid").toString()));
            if (!ObjectUtils.isEmpty(orderVo.getRecId())){
                orderVo.setRecId(Integer.parseInt(hashOperations.get("epai:order:"+id,"recId").toString()));
            }
            orderVo.setBasePrice(new BigDecimal(hashOperations.get("epai:order:"+id,"basePrice").toString()));
            orderVo.setBond(new BigDecimal(hashOperations.get("epai:order:"+id,"bond").toString()));
            orderVo.setPrice(new BigDecimal(hashOperations.get("epai:order:"+id,"price").toString()));
            orderVo.setStarttime(DateUtil.stringToDate(hashOperations.get("epai:order:"+id,"starttime").toString()));
            if (!ObjectUtils.isEmpty(orderVo.getTransactionPrice())){
                orderVo.setTransactionPrice(new BigDecimal(hashOperations.get("epai:order:"+id,"transactionPrice").toString()));
            }
            //将订单信息存入集合
            orderVos.add(orderVo);
        });


        return orderVos;
    }

    /**
     * 修改redis中订单的状态
     * @param status
     */
    @Override
    public void updateRedisOrderStatus(Integer oid,Integer status) {
        HashOperations<String, Object, Object> hashOperations = stringRedisTemplate.opsForHash();
        hashOperations.put("epai:order:"+oid.toString(),"orderStatus",status.toString());
    }


}
